package com.zzyl.nursing.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.framework.web.service.TokenService;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.domain.Elder;
import com.zzyl.nursing.dto.UserLoginRequestDto;
import com.zzyl.nursing.mapper.ElderMapper;
import com.zzyl.nursing.service.WechatService;
import com.zzyl.nursing.dto.ElderlyInfoDto;
import com.zzyl.nursing.vo.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.FamilyMemberMapper;
import com.zzyl.nursing.domain.FamilyMember;
import com.zzyl.nursing.service.IFamilyMemberService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * 老人家属Service业务层处理
 *
 * @author ruoyi
 * @date 2025-04-26
 */
@Service
public class FamilyMemberServiceImpl extends ServiceImpl<FamilyMemberMapper, FamilyMember> implements IFamilyMemberService {
    @Autowired
    private FamilyMemberMapper familyMemberMapper;

    @Autowired
    private ElderMapper elderMapper;

    static List<String> DEFAULT_NICKNAME_PREFIX = ListUtil.of(
            "生活更美好",
            "大桔大利",
            "日富一日",
            "好柿开花",
            "柿柿如意",
            "一椰暴富",
            "大柚所为",
            "杨梅吐气",
            "天生荔枝"
    );

    /**
     * 查询老人家属
     *
     * @param id 老人家属主键
     * @return 老人家属
     */
    @Override
    public FamilyMember selectFamilyMemberById(Long id) {
        return getById(id);
    }

    /**
     * 查询老人家属列表
     *
     * @param familyMember 老人家属
     * @return 老人家属
     */
    @Override
    public List<FamilyMember> selectFamilyMemberList(FamilyMember familyMember) {
        return familyMemberMapper.selectFamilyMemberList(familyMember);
    }

    /**
     * 新增老人家属
     *
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int insertFamilyMember(FamilyMember familyMember) {
        return save(familyMember) ? 1 : 0;
    }

    /**
     * 修改老人家属
     *
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int updateFamilyMember(FamilyMember familyMember) {
        return updateById(familyMember) ? 1 : 0;
    }

    /**
     * 批量删除老人家属
     *
     * @param ids 需要删除的老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberByIds(Long[] ids) {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除老人家属信息
     *
     * @param id 老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberById(Long id) {
        return removeById(id) ? 1 : 0;
    }

    @Autowired
    private WechatService wechatService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 小程序端登录
     * @param dto
     * @return
     */
    @Override
    public LoginVo login(UserLoginRequestDto dto) {

        //获取openid  微信接口获取
        String openid = wechatService.getOpenid(dto.getCode());

        //根据openid查询用户信息
        FamilyMember familyMember = getOne(Wrappers.<FamilyMember>lambdaQuery().eq(FamilyMember::getOpenId, openid));

        //如果用户为空，构建用户，赋值一个openid
        if (ObjectUtil.isEmpty(familyMember)) {
            familyMember = FamilyMember
                    .builder()
                    .openId(openid)
                    .build();
        }

        //获取用户的手机号  微信接口获取
        String phone = wechatService.getPhone(dto.getPhoneCode());

        //保存或更新用户
        insertOrUpdateFamilyMember(familyMember, phone);

        //生成token返回
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", familyMember.getId());
        claims.put("userName", familyMember.getName());

        String token = tokenService.createToken(claims);
        LoginVo loginVo = new LoginVo();
        loginVo.setNickName(familyMember.getName());
        loginVo.setToken(token);

        return loginVo;
    }

    @Override
    public void add(ElderlyInfoDto dto) {
        //从线程中获取用户信息
        Long userId = UserThreadLocal.getUserId();
        if (userId == null) {
            throw new BaseException("请先登录");
        }
        //前往数据库查询老人姓名和身份证号是否存在
        int temp = elderMapper.countByCardAndName(dto.getIdCard(), dto.getName());
        if (temp == 0) {
            throw new BaseException("该老人不存在,请检查身份号或姓名");
        }
        //根据老人身份证号查询老人主键
        Elder elder = elderMapper.selectOne(Wrappers.<Elder>lambdaQuery().eq(Elder::getIdCardNo, dto.getIdCard()));

        LocalDateTime time = LocalDateTime.now();

        //查询该用户是否已经绑定该老人，如果已绑定则抛出异常
        FamilyMember familyMember = familyMemberMapper.selectFamilyMemberBingdingElder(userId, elder.getId());
        if (familyMember != null) {
            throw new BaseException("该用户已绑定过该老人");
        }

        //老人存在，开始存储数据到中间表family_member_elder
        familyMemberMapper.addElderAndMember(userId, elder.getId(), userId, userId, time, time, dto.getRemark());

    }

    @Override
    public List<FamilyMemberElderVo> getMyFamilyElder() {
        Long userId = UserThreadLocal.getUserId();
        //获取用户下的所有老人
        return familyMemberMapper.getMyFamilyElder(userId);
    }

    @Override
    public PageInfo<FamilyMemberElderRelationVO> listByPage(Integer pageNum, Integer pageSize) {
        Long userId = UserThreadLocal.getUserId();
        // 1. 启动分页（紧跟在查询方法前调用）
        PageHelper.startPage(pageNum, pageSize);

        // 2. 执行查询（此时返回的是全部数据，但PageHelper会拦截并分页）
        List<FamilyMemberElderRelationVO> list = familyMemberMapper.listByPage(userId);

        // 3. 封装为PageInfo对象（包含分页信息）
        return new PageInfo<>(list);
    }

    @Override
    public List<DeviceDataVo> queryServiceProperties(String iotId) {
        //从redis中获取设备数据
        redisTemplate.opsForHash().get(CacheConstants.IOT_DEVICE_LAST_DATA, iotId);
        String jsonStr = (String) redisTemplate.opsForHash().get(CacheConstants.IOT_DEVICE_LAST_DATA, iotId);
        if (StringUtils.isEmpty(jsonStr)) {
            return Collections.emptyList();
        }
        List<DeviceData> list = JSONUtil.toList(jsonStr, DeviceData.class);

        List<DeviceDataVo> deviceDataVos = new ArrayList<>();
        //遍历设备数据
        list.forEach(deviceData -> {
            DeviceDataVo deviceDataVo = new DeviceDataVo();
            //设置功能标识
            deviceDataVo.setFunctionId(deviceData.getFunctionId());
            //设置时间
            deviceDataVo.setEventTime(deviceData.getAlarmTime());
            //设置设备值
            deviceDataVo.setValue(deviceData.getDataValue());
            //提交
            deviceDataVos.add(deviceDataVo);
        });

        return deviceDataVos;
    }

    /**
     * 保存或更新用户
     * @param familyMember
     * @param phone
     */
    private void insertOrUpdateFamilyMember(FamilyMember familyMember, String phone) {

        //判断手机号与数据库的手机号是否一致
        if (ObjectUtil.notEqual(familyMember.getPhone(), phone)) {
            familyMember.setPhone(phone);
        }
        //判断是否存在id，如果存在id，则更新，不存在则保存
        if (ObjectUtil.isNotEmpty(familyMember.getId())) {
            updateById(familyMember);
            return;
        }
        //获取用户的昵称
        int index = (int) (Math.random() * DEFAULT_NICKNAME_PREFIX.size());
        String nickName = DEFAULT_NICKNAME_PREFIX.get(index) + StringUtils.substring(phone, 7, 11);
        familyMember.setName(nickName);
        //保存
        save(familyMember);

    }

    @Override
    public List<TimeSeriesDataVO> queryDeviceDataListByDay(String iotId, String functionId, Long startTime, Long endTime) {
        //传输进来的是毫秒值，将毫秒值转换为LocalDateTime类型
        LocalDateTime startTimeLocalDateTime = LocalDateTimeUtil.of(startTime);
        LocalDateTime endTimeLocalDateTime = LocalDateTimeUtil.of(endTime);

        //获取时间段数组
        List<LocalDateTime> localDateTimes = generateTimeSlots(startTimeLocalDateTime, endTimeLocalDateTime);

        ArrayList<TimeSeriesDataVO> timeSeriesDataVOS = new ArrayList<>();
        for (int i = 0; i < localDateTimes.size(); i++) {
            TimeSeriesDataVO timeSeriesDataVO = new TimeSeriesDataVO();
            //当前时间
            LocalDateTime nowTime = localDateTimes.get(i);
            //如果值没有超过数组长度则查询下一个值，如果超过了则查询上一个值
            if (i < localDateTimes.size() - 1) {
                LocalDateTime nextTime = localDateTimes.get(i + 1);
                //查询当前时间段的值
                Double timeSlotsAvg = familyMemberMapper.getTimeSlotsAvg(iotId, functionId, nowTime, nextTime);
                timeSeriesDataVO.setDataValue(timeSlotsAvg);
                //将nextTime转换为HH:mm的string格式
                timeSeriesDataVO.setDateTime(nextTime.format(DateTimeFormatter.ofPattern("HH:mm")));



                //存放value
                if (timeSlotsAvg == null){
                    timeSeriesDataVO.setDataValue(0.0);
                }else {
                    //四舍五入
                    timeSlotsAvg = roundDouble(timeSlotsAvg);
                    timeSeriesDataVO.setDataValue(timeSlotsAvg);
                }
            }else {
                LocalDateTime beforeTime = localDateTimes.get(i - 1);
                //查询当前时间段的值
                Double timeSlotsAvg = familyMemberMapper.getTimeSlotsAvg(iotId, functionId, beforeTime, nowTime);
                //将nextTime转换为HH:mm的string格式
                timeSeriesDataVO.setDateTime(beforeTime.format(DateTimeFormatter.ofPattern("HH:mm")));

                //存放value
                if (timeSlotsAvg == null){
                    timeSeriesDataVO.setDataValue(0.0);
                }else {
                    //四舍五入
                    timeSlotsAvg = roundDouble(timeSlotsAvg);
                    timeSeriesDataVO.setDataValue(timeSlotsAvg);
                }
            }
            //保存到list
            timeSeriesDataVOS.add(timeSeriesDataVO);
        }

        return timeSeriesDataVOS;
    }

    /**
     * 生成24小时时间段
     * @return 时间段数组
     */
    public static List<LocalDateTime> generateTimeSlots(LocalDateTime startTime, LocalDateTime endTime) {
        List<LocalDateTime> slots = new ArrayList<>();

        // 参数校验
        if (startTime.isAfter(endTime)) {
            throw new IllegalArgumentException("开始时间不能晚于结束时间");
        }

        // 获取开始时间的整点（去掉分钟和秒）
        LocalDateTime current = startTime.withMinute(0).withSecond(0).withNano(0);

        // 如果开始时间不是整点，则从下一个整点开始
        if (current.isBefore(startTime)) {
            current = current.plusHours(1);
        }

        // 生成时间点
        while (!current.isAfter(endTime)) {
            slots.add(current);
            current = current.plusHours(1);
        }

        return slots;
    }

    @Override
    public List<TimeSeriesDataVO> queryWeeklyHeartRateData(String iotId,String functionId, Long startTime, Long endTime) {
        // 将毫秒值转换为LocalDateTime类型
        LocalDateTime startTimeLocalDateTime = LocalDateTimeUtil.of(startTime);
        LocalDateTime endTimeLocalDateTime = LocalDateTimeUtil.of(endTime);

        // 获取一周的时间段数组（按天分组）
        List<LocalDateTime> weekDays = generateWeekTimeSlots(startTimeLocalDateTime, endTimeLocalDateTime);

        List<TimeSeriesDataVO> weeklyData = new ArrayList<>();
        for (int i = 0; i < weekDays.size(); i++) {
            TimeSeriesDataVO dailyData = new TimeSeriesDataVO();
            LocalDateTime currentDay = weekDays.get(i);

            // 如果是最后一天，则使用前一天作为结束时间
            if (i < weekDays.size() - 1) {
                LocalDateTime nextDay = weekDays.get(i + 1);
                Double dailyAvg = familyMemberMapper.getDailyHeartRateAvg(
                        iotId,
                        functionId,
                        currentDay,
                        nextDay
                );

                // 设置日期显示格式（周几）
                dailyData.setDateTime(currentDay.format(DateTimeFormatter.ofPattern("E", Locale.CHINA)));
                dailyData.setDataValue(roundDouble(dailyAvg));
            } else {
                LocalDateTime previousDay = weekDays.get(i - 1);
                Double dailyAvg = familyMemberMapper.getDailyHeartRateAvg(
                        iotId,
                        functionId,
                        previousDay,
                        currentDay
                );

                dailyData.setDateTime(previousDay.format(DateTimeFormatter.ofPattern("E", Locale.CHINA)));
                dailyData.setDataValue(roundDouble(dailyAvg));
            }

            weeklyData.add(dailyData);
        }

        return weeklyData;
    }

    @Override
    public void deleteFamilyElderMemberById(Long id) {
        familyMemberMapper.deleteFamilyElderMemberById(id);
    }

    // 生成一周的时间段（每天一个点）
    private List<LocalDateTime> generateWeekTimeSlots(LocalDateTime start, LocalDateTime end) {
        List<LocalDateTime> days = new ArrayList<>();
        LocalDateTime current = start;

        while (!current.isAfter(end)) {
            days.add(current);
            current = current.plusDays(1);
        }

        // 确保包含结束时间
        if (!days.get(days.size() - 1).isEqual(end)) {
            days.add(end);
        }

        return days;
    }

    // 四舍五入工具方法
    private Double roundDouble(Double value) {
        if (value == null) {
            return 0.0;
        }
        return BigDecimal.valueOf(value)
                .setScale(2, RoundingMode.HALF_UP)
                .doubleValue();
    }
}


